package com.wangyadong.hobby.thread.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * <p>
 *
 * @author <714037465@qq.com>
 * @since 2019/7/117:24
 **/
public abstract class TCPNioServer implements Runnable {

    protected ServerSocketChannel channel = null;
    private boolean done = false;
    protected Selector selector;
    protected int port = 8888;

    public void startServer() throws IOException {
        channel = ServerSocketChannel.open();
        channel.configureBlocking(false);
        ServerSocket server = channel.socket();
        server.bind(new InetSocketAddress(port));
        selector = Selector.open();
        channel.register(selector, SelectionKey.OP_ACCEPT);
    }

    public void stopServer() throws IOException {
        done = true;
        channel.close();
    }

    public boolean getDone() {
        return this.done;
    }

    @Override
    public void run() {
        try {
            startServer();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        while (!getDone()) {
            try {
                selector.select();
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
        }

        Iterator<SelectionKey> it = selector.selectedKeys().iterator();
        while (it.hasNext()) {
            SelectionKey key = it.next();
            if (key.isReadable() || key.isWritable()) {
                try {
                    handleServer(key);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void handleServer(SelectionKey key) throws IOException {
        SocketChannel sc = channel.accept();
        sc.configureBlocking(false);
        sc.register(selector, SelectionKey.OP_READ);
        registeredClient(sc);
    }

    public abstract void handleClient(SelectionKey key) throws IOException;

    public abstract void registeredClient(SocketChannel sc) throws IOException;


}
